package com.slipper.system.codeless.controller;

import com.alibaba.excel.EasyExcel;
import com.slipper.core.excel.ExcelReadListener;
import com.slipper.core.gson.GsonUtil;
import com.slipper.system.backup.service.BackupRestoreService;
import com.slipper.system.codeless.bo.*;
import com.slipper.system.codeless.service.*;
import com.slipper.system.codeless.vo.DataModelVO;
import com.slipper.util.*;
import jakarta.annotation.Resource;

import com.slipper.constants.Constants;
import com.slipper.core.tree.Node;
import com.slipper.core.tree.Tree;
import com.slipper.core.tree.TreeInfo;
import com.slipper.core.tree.TreeUtil;
import jakarta.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.nio.charset.StandardCharsets;
import java.util.*;

/**
 * 数据模型信息表
 */
@RestController
@RequestMapping("/system/dataModel")
public class DataModelController {
    private static final Logger logger = LoggerFactory.getLogger(DataModelController.class);

    @Resource
    private DataModelService dataModelService;
    @Resource
    private DataFolderService dataFolderService;
    @Resource
    private BackupRestoreService backupRestoreService;
    
    @PostMapping(value = "/queryBy")
    public String queryBy(@RequestBody DataModelBO bo) {
        if(Tool.isBlank(bo.getId())) {
            return ResultUtil.failureResult("数据获取失败！");
        }
        return ResultUtil.successResult(dataModelService.queryBy(bo.getId()));
    }

    @PostMapping(value = "/queryList")
    public String queryList(@RequestBody DataModelBO bo) {
        return ResultUtil.successResult(dataModelService.queryList(bo));
    }
    
    @PostMapping(value = "/queryPage")
    public String queryPage(@RequestBody DataModelBO bo) {
        return ResultUtil.successResult(dataModelService.queryPage(bo));
    }

    @PostMapping(value = "/save")
    public String save(@RequestBody DataModelBO bo) {
        if (bo.getFieldList() == null || bo.getFieldList().isEmpty()) {
            return ResultUtil.failureResult("字段不能为空！");
        }
        bo.setOperateId(Constants.getCurrentUser().getEmployeeId());
        return ResultUtil.saveResult(dataModelService.save(bo), bo);
    }

    @PostMapping(value = "/delete")
    public String delete(@RequestBody DataModelBO bo) {
        return ResultUtil.deleteResult(dataModelService.delete(bo));
    }

    @PostMapping("/queryTree")
    public String queryTree() {
        List<DataFolderBO> folderList = dataFolderService.queryList(new DataFolderBO());
        TreeInfo folderTreeInfo = new TreeInfo("目录树");
        folderTreeInfo.setRootId(Constants.ROOT_ID);
        folderTreeInfo.setIdField("id");
        folderTreeInfo.setPidField("parentId");
        folderTreeInfo.setTextField("name");
        folderTreeInfo.setNodeType("folder");
        folderTreeInfo.setSortField("ordinal");

        DataModelBO dataModelBO = new DataModelBO();
        dataModelBO.setSortField("name asc");
        List<DataModelBO> modelList = this.dataModelService.queryList(dataModelBO);
        modelList.stream().filter(item -> Tool.isBlank(item.getFolderId()))
                .forEach(item -> item.setFolderId(Constants.ROOT_ID));

        TreeInfo modelTreeInfo = new TreeInfo("");
        modelTreeInfo.setIdField("id");
        modelTreeInfo.setPidField("folderId");
        modelTreeInfo.setTextField("name");
        modelTreeInfo.setNodeType("model");
        modelTreeInfo.setSortField("ordinal");

        Node rootNode = TreeUtil.buildTree(
                "asc",
                new Tree(folderTreeInfo, BeanUtil.setOrdinal(folderList)),
                new Tree(modelTreeInfo, BeanUtil.setOrdinal(modelList)));
        return ResultUtil.successResult(rootNode);
    }

    @PostMapping(value = "/updateFolder")
    public String updateFolder(@RequestBody DataModelBO bo) {
        bo.setOperateId(Constants.getCurrentUser().getEmployeeId());
        return ResultUtil.saveResult(dataModelService.updateFolder(bo), bo);
    }

    @PostMapping(value = "/downloadTpl")
    public void downloadTpl(HttpServletResponse response) {
        FileUtil.downloadTpl(response, "dataModel.xlsx", "数据模型模板.xlsx");
    }

    @PostMapping(value = "/uploadXls")
    public String uploadXls(DataModelBO bo) {
        if (bo.getFile() == null) {
            return ResultUtil.failureResult("上传文件不存在！");
        }

        try {
            ExcelReadListener listener = new ExcelReadListener();
            EasyExcel.read(bo.getFile().getInputStream(), listener).sheet().headRowNumber(0).doRead();

            List<DataModelBO> dataModelList = new ArrayList<>();
            StringBuilder builder = new StringBuilder();
            int i = 1;
            for (List<Map<Integer, String>> dataList : listener.getSheetDataList()) {
                DataModelBO dataModel = checkAndConvert(dataList, "第" + i + "个sheet", builder);
                if (dataModel != null) {
                    dataModelList.add(dataModel);
                }
            }
            if (!builder.isEmpty()) {
                return ResultUtil.failureResult("2", builder.substring(3));
            }
            if (dataModelList.isEmpty()) {
                return ResultUtil.failureResult("上传的数据为空，请先录入数据！");
            }

            dataModelList.forEach(dataModel -> dataModelService.save(dataModel));
            return ResultUtil.successResult("数据模型导入成功。");
        } catch (Exception e) {
            logger.error("文件解释出错!", e);
            return ResultUtil.failureResult("文件解释错误：" + e.getMessage());
        }
    }

    private DataModelBO checkAndConvert(List<Map<Integer, String>> dataList, String prefix, StringBuilder message) {
        if (dataList.size() < 4) {
            return null;
        }

        DataModelBO dataModel = new DataModelBO();
        // 第0行，第1列：目录名称
        dataModel.setFolderName(dataList.getFirst().get(1));
        // 第1行、第1列：模型类型
        dataModel.setType(dataList.get(1).get(1));
        if (Tool.isBlank(dataModel.getType())) {
            message.append("@@@").append(prefix).append(": 模型类型不能为空！");
            return null;
        }
        if (Tool.isBlank(dataModel.getType()) || !"库表、视图".contains(dataModel.getType())) {
            message.append("@@@").append(prefix).append("：模型类型不正确，可选值[库表、视图]！");
            return null;
        } else {
            if ("库表".equals(dataModel.getType())) {
                dataModel.setType(Constants.DataModel.TYPE_TABLE);
            } else if ("视图".equals(dataModel.getType())) {
                dataModel.setType(Constants.DataModel.TYPE_VIEW);
            }
        }

        // 第1行、第3列：模型名称
        dataModel.setName(String.valueOf(dataList.get(1).get(3)));
        if (Tool.isBlank(dataModel.getName())) {
            message.append("@@@").append(prefix).append(": 模型名称不能为空！");
            return null;
        }
        if (dataModel.getName().length() > 100) {
            message.append("@@@").append(prefix).append(": 模型名称长度不能大于100！");
            return null;
        }

        // 第4行开始为数据
        List<DataFieldBO> dataFieldList = getDataFieldList(dataList, prefix, message);

        if (dataFieldList.isEmpty()) {
            message.append("@@@").append(prefix).append(": 字段数据不能为空！");
            return null;
        }

        dataModel.setFieldList(dataFieldList);
        return dataModel;
    }

    private static List<DataFieldBO> getDataFieldList(
            List<Map<Integer, String>> dataList,
            String prefix,
            StringBuilder message) {
        List<DataFieldBO> dataFieldList = new ArrayList<>();
        for (int i = 3; i<dataList.size(); i++) {
            String rowPrefix = "@@@" + prefix + "第" + (i + 1) + "行：";
            Map<Integer, String> data = dataList.get(i);

            DataFieldBO dataField = new DataFieldBO();
            dataField.setFieldName(data.get(0));
            dataField.setShowName(data.get(1));
            dataField.setRequired(data.get(2));
            dataField.setFieldType(data.get(3));
            dataField.setFieldSize(data.get(4) == null ? null : Integer.parseInt(data.get(4)));
            dataField.setFieldPrecision(data.get(5) == null ? null : Integer.parseInt(data.get(5)));
            dataField.setEnumerate(data.get(7));
            dataField.setEnumerateValue(data.get(8));
            dataField.setDescription(data.get(9));

            if (Tool.isBlank(dataField.getFieldName())) {
                message.append(rowPrefix).append("字段名称不能为空！");
                continue;
            }
            if (dataField.getFieldName().length() > 50) {
                message.append(rowPrefix).append("字段名称长度不能大于50个字符！");
                continue;
            }
            if (Tool.isBlank(dataField.getShowName())) {
                message.append(rowPrefix).append("显示名称不能为空！");
                continue;
            }
            if (dataField.getFieldSize() != null && dataField.getFieldSize() > 4000) {
                message.append(rowPrefix).append("字段长度不能大于4000！");
                continue;
            }
            if (dataField.getFieldPrecision() != null && dataField.getFieldPrecision() > 10) {
                message.append(rowPrefix).append("字段精度不能大于10！");
                continue;
            }
            if (dataField.getShowName().length() > 100) {
                message.append(rowPrefix).append("显示名称长度不能大于100个字符！");
                continue;
            }
            if (dataField.getDescription() != null && dataField.getDescription().length() > 1000) {
                message.append(rowPrefix).append("字段描述长度不能大于1000个字符！");
                continue;
            }
            if (Tool.isBlank(dataField.getRequired()) || !"是、否".contains(dataField.getRequired())) {
                message.append(rowPrefix).append("是否必填不正确，可选值[是、否]！");
                continue;
            } else {
                if ("是".equals(dataField.getRequired())) {
                    dataField.setRequired(Constants.YES);
                } else if ("否".equals(dataField.getRequired())) {
                    dataField.setRequired(Constants.NO);
                }
            }
            if (Tool.isBlank(dataField.getFieldType())
                    || Arrays.stream("字符、整数、小数、日期、时间、图片、视频、附件、大文本".split("、"))
                        .noneMatch(item -> item.equals(dataField.getFieldType()))) {
                message.append(rowPrefix).append("字段类型不正确，可选值[字符、整数、小数、日期、时间、图片、视频、附件、大文本]！");
                continue;
            }
            if (DataFieldBO.FIELD_TYPE_VARCHAR.equals(dataField.getFieldType())
                    && Tool.isNotBlank(dataField.getEnumerate())
                    && !"是、否".contains(dataField.getEnumerate())) {
                message.append(rowPrefix).append("是否枚举不正确，可选值[是、否]！");
                continue;
            } else {
                if ("是".equals(dataField.getRequired())) {
                    dataField.setEnumerate(Constants.YES);
                } else if ("否".equals(dataField.getRequired())) {
                    dataField.setEnumerate(Constants.NO);
                }
            }
            if (DataFieldBO.FIELD_TYPE_VARCHAR.equals(dataField.getFieldType()) && Constants.YES.equals(dataField.getEnumerate())) {
                dataField.setEnumerateType(data.get(6));
                if (Tool.isBlank(dataField.getEnumerateType())
                        || Arrays.stream("单选框、下拉框".split("、"))
                            .noneMatch(item -> item.equals(dataField.getEnumerateType()))) {
                    message.append(rowPrefix).append("输入框类型不正确，可选值[单选框、下拉框]！");
                    continue;
                }
                if (Tool.isBlank(dataField.getEnumerateType())) {
                    message.append(rowPrefix).append("枚举值不能为空！");
                    continue;
                }
                dataField.setEnumerateValue(dataField.getEnumerateValue().replaceAll("，", ","));
            } else if (DataFieldBO.FIELD_TYPE_VARCHAR.equals(dataField.getFieldType()) && Constants.NO.equals(dataField.getEnumerate())) {
                dataField.setInputType(data.get(6));
                if (Tool.isNotBlank(dataField.getInputType())
                        && Arrays.stream("单行文本框、密码文本框、多行文本框".split("、"))
                            .noneMatch(item -> item.equals(dataField.getInputType()))) {
                    message.append(rowPrefix).append("输入框类型不正确，可选值[单行文本框、密码文本框、多行文本框]！");
                    continue;
                }
            }
            dataFieldList.add(dataField);
        }
        return dataFieldList;
    }

    @PostMapping(value = "/exportData")
    public void exportData(HttpServletResponse response, @RequestBody Map<String, Object> data) {
        String fileName = "model-" + DateUtil.format(new Date(), "dd-HH-mm-ss") + ".dat";
        DataModelVO vo = backupRestoreService.backupDataModel(data);
        FileUtil.downloadContent(response, fileName, AESUtil.encrypt(GsonUtil.toJson(vo)));
    }

    @PostMapping(value = "/importData")
    public String importData(DataModelBO bo) {
        if (bo.getFile() == null) {
            return ResultUtil.failureResult("请选择上传文件！");
        }
        try {
            String content = new String(bo.getFile().getBytes(), StandardCharsets.UTF_8);
            backupRestoreService.restoreDataModel(AESUtil.decrypt(content));
            return ResultUtil.successResult("导入数据模型成功。");
        } catch (Exception e) {
            logger.error("文件解释出错！", e);
            return ResultUtil.failureResult("文件解释出错！");
        }
    }
}